home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
fastlane.arc
/
TIMER.ASM
< prev
next >
Wrap
Assembly Source File
|
1985-10-20
|
14KB
|
312 lines
page 60, 120
;----------------------------------------------------------------------------;
; High Resolution Timer Test Program ;
; ;
; Based on: Smith, B and T Puckett "Life in the Fast Lane", PC TECH ;
; JOURNAL, vol. 1, no. 7, April 1984, pp. 62-74. ;
; ;
; Modified by: TA Fischer ;
; ;
; Modifications to code in article: ;
; ;
; 1) The calibration and code to be tested sections have been broken ;
; out into separate subroutines. This means that no modification of ;
; this code is necessary to run timings. Simply set up the two ;
; subroutines as noted below, assemble them separately, and link ;
; in this code. ;
; ;
; 2) The number of clock ticks is printed out (albeit crudely), so ;
; one does not have to use debug to run this. ;
; ;
; ;
; This is a control routine to be used in running high resolution ;
; timer tests. The code to be tested should be placed in two ;
; subroutines: "CALIB", containing any code whose effect is to be ;
; removed from the results (loop control, etc.), and "TEST", which ;
; should contain the actual code to be tested. The subroutines ;
; should be assembled separately and linked with these routines. ;
; The following format should be used for the test routines: ;
; ;
; ;
; data segment public byte ;
; ; declare here any storage required by test routines ;
; data ends ;
; ;
; ;
; code segment public byte ;
; assume cs: code ;
; ;
; public calib ;
; calib proc near ;
; ; place the calibration code here ;
; ret ;
; calib endp ;
; ;
; public test ;
; test proc near ;
; ; place the test code here ;
; ret ;
; test endp ;
; ;
; code ends ;
; end ;
; ;
; The routine prints out the number of 0.84 microsecond clock ticks (in hex) ;
;----------------------------------------------------------------------------;
page
stack segment stack para
db 32 dup ('stack ')
stack ends
data segment public byte
a_cal_high dw ? ; first timer readings
a_cal_low dw ? ;
a_cal_ext dw ? ;
b_cal_high dw ? ; second timer readings
b_cal_low dw ? ;
b_cal_ext dw ? ;
hextable db '0123456789ABCDEF'
outstr db '000000000000$'
data ends
bios_data_seg equ 40h
bios_data segment at 40h
org 6Ch
timer_low dw ?
timer_high dw ?
bios_data ends
code segment public byte
assume cs: code
timer_0 equ 40h ; 8293 counter port 0
timer_ctl equ 43h ; 8253 control port
timer_lat equ 00h ; 8253 command to save ch. 0 current count
timer_set equ 00110100b ; 8253 counter 0, mode 2, binary
page
;----------------------------------------------------------------------------;
; Program TIMERT03 -- High Resolution Timer Test Skeleton ;
; ;
; This is a skeleton of a control routine to be used in running ;
; high resolution timer tests. The code to be tested is included ;
; in this module or called from it. This routine calls subroutines ;
; TIMERR01 and TIMERS02 for setting and reading Counter 0 of the 8253. ;
; It is normally run under DEBUG to allow a breakpoint to be set to ;
; examine the results of the timing test. ;
;----------------------------------------------------------------------------;
extrn calib: near ; calibration routine
extrn test: near ; test routine
public TIMERT03
TIMERT03 proc far
push ds ; make return linkage
xor ax, ax
push ax
mov ax, data ; get data segment addressable
mov ds, ax
assume ds: data
tester: call timers01 ; get 8253 counter 0 running in Mode 2
call timerr02 ; begin calibration pass
call timerr02 ; seem to need an extra one here
mov a_cal_ext, cx
mov a_cal_low, bx
mov a_cal_high, ax ; initial extended timer count now saved
;------------------------------------------------------------------;
; Beginning of calibration pass ;
;------------------------------------------------------------------;
; Put here any test code whose effect is to be removed from the
; results, such as loop control statements ...
call calib ; Call routine containing calibration code
;------------------------------------------------------------------;
; End of calibration pass ;
;------------------------------------------------------------------;
call timerr02 ; end of calibration pass, begin test pass
mov b_cal_ext, cx
mov b_cal_low, bx
mov b_cal_high, ax
;------------------------------------------------------------------;
; Beginning of test pass ;
;------------------------------------------------------------------;
; Put test code here ...
call test ; Call routine containing test code
;------------------------------------------------------------------;
; End of test pass ;
;------------------------------------------------------------------;
call timerr02 ; end of test pass
add cx, a_cal_ext ; calculate (C-B)-(B-A) as ((C+A)-B)-B
adc bx, a_cal_low ; ADC to allow for carry in preceding ADD
adc ax, a_cal_high ; now have C+A
sub cx, b_cal_ext ; Compute (C+A)-B
sbb bx, b_cal_low
sbb ax, b_cal_high
sub cx, b_cal_ext ; Compute ((C+A)-B)-B in timer counts
sbb bx, b_cal_low ; as a 6 byte field in AX, BX, and CX
sbb ax, b_cal_high
halt: push ax
mov ax, ds
mov es, ax
mov di, offset outstr
pop ax
call regtohex
mov ax, bx
call regtohex
mov ax, cx
call regtohex
mov dx, offset outstr
mov ah, 9
int 21h
ret
TIMERT03 endp
page
;----------------------------------------------------------------------------;
; Public Procedure TIMERS01 -- High Resolution Timer Setup ;
; ;
; This is a subroutine to set up Counter 0 of the 8253 to run in Mode 2. ;
; It normally runs in Mode 3, which makes its residual count values ;
; useless for high resolution timing purposes since in this mode it ;
; counts down by twos, with two countdowns per cycle. In Mode 2, there ;
; is a single countdown per cycle, by ones, so the residual count values ;
; are meaningful. (See routine TIMERR02 for recovering timing ;
; information.) ;
;----------------------------------------------------------------------------;
public TIMERS01
TIMERS01 proc near
push ax ; preserve
push cx
mov al, timer_set ; set Counter 0 parameters, prime
out timer_ctl, al ; load trigger
xor al, al ; zero will give full count of 65536
nop ; insure 5 clocks for 8253 recovery time
out timer_0, al ; load low order byte
nop ; 8253 recovery time
nop ; " " "
out timer_0, al ; load high order byte
mov cx, 20000 ; must be sure previous countdown done
loop: loop loop ; so spin here 70 ms to guarantee it
pop cx ; restore
pop ax
ret
TIMERS01 endp
page
;----------------------------------------------------------------------------;
; Public Procedure TIMERR02 -- High Resolution Timer Read Routine ;
; ;
; This is a subroutine to return high resolution timing information ;
; obtained from the BIOS TIMER_LOW and TIMER_HIGH fields, extended ;
; with low order information obtained from the current residual count ;
; of Counter 0 of the 8253. (See routine TIMERS01 for initializing ;
; Counter 0.) ;
;----------------------------------------------------------------------------;
public TIMERR02
TIMERR02 proc near
push ds ; get pointer to BIOS data area
mov ax, bios_data_seg
mov ds, ax
assume ds: bios_data
mov al, timer_lat ; timer 0, latch
cli ; hold off interrupts while fetching data
out timer_ctl, al ; latch current count in 8253
mov bx, timer_low ; get matching values
mov cx, timer_high ;
in al, timer_0 ; read in low order byte
mov ah, al ; tuck it out of the way
nop ; insure 5 clocks for 8253 recovery
in al, timer_0 ; read in high order byte
sti ; allow interrupts again
xchg ah, al ; get in right order in register
neg ax ; get up count from down
xchg ax, cx ; return in common register orter
pop ds
ret
TIMERR02 endp
page
; Convert register AX to a hex string located at ES:DI
public regtohex
regtohex proc near
assume ds: data
push bx
push cx
push dx
cld
mov cl, 4
mov dx, ax
mov bx, offset hextable
shr ax, cl
and ax, 0F0Fh ; mask for first and third nibble
and dx, 0F0Fh ; mask for second and fourth nibble
xchg ah, al ; upper nibble
xlat
stosb
mov al, dh ; second nibble
xlat
stosb
mov al, ah ; third nibble
xlat
stosb
mov al, dl ; lower nibble
xlat
stosb
pop dx
pop cx
pop bx
ret
regtohex endp
code ends
end TIMERT03